﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace SpaceEngine
{
    public class Camera
    {
        public Matrix World;
        public Matrix View;
        public Matrix ViewInverse;
        public Matrix Projection;
        public Matrix WorldViewProjection;

        Game1 game;
        Vector3 position;
        Vector3 targetPosition;
        float cullDist;
        float zoomSpeed;
        float strafeSpeed;

        const float DEFAULT_ZOOM = 50;
        float currentZoom;

        const float DEFAULT_ELEVATION = 100;
        float currentElevation;

        public Camera(Game1 game)
        {
            this.game = game;
            cullDist = 20000f;
            strafeSpeed = .50f;
            zoomSpeed = .20f;
            currentZoom = DEFAULT_ZOOM;
            currentElevation = DEFAULT_ELEVATION;
            position =  new Vector3(currentZoom, currentElevation, currentZoom);
            targetPosition = Vector3.Zero;
            

            World = Matrix.Identity; // the game world
            View = Matrix.Identity; // what we're looking at
            DeriveProjection(); // create the lens, facing the target
        }

        public void Update()
        {
            // get keyboard info
            KeyboardState kb = game.input.keyboard;

            // set position based on target and zoom
            SetPosition();

            // reset camera
            if (kb.IsKeyDown(Keys.Space))
            {
                currentZoom = DEFAULT_ZOOM;
                currentElevation = DEFAULT_ELEVATION;
            }

            // zoom in/out
            if (currentElevation <= 200)
            {
                if (kb.IsKeyDown(Keys.Down))
                {
                    currentElevation += strafeSpeed;
                    currentZoom += zoomSpeed;
                }
            }
            if(currentElevation >= 0)
            {
                if (kb.IsKeyDown(Keys.Up))
                {
                    currentElevation -= strafeSpeed;
                    currentZoom -= zoomSpeed;
                }
            }

            // create camera position (absolute)
            ViewInverse.Translation = position;

            // derive world/ view projections
            // do each frame in case user resizes
            DeriveProjection();
            View = Matrix.CreateLookAt(position,targetPosition,Vector3.Up);
            WorldViewProjection = World * View * Projection;
        }

        void DeriveProjection()
        {
            // aspect ratio is set by viewport width/height
            // always 90 vertical FOV, horizontal based on viewport
            Projection = Matrix.CreatePerspective(game.GraphicsDevice.Viewport.Width / game.GraphicsDevice.Viewport.Height, 1, 1, cullDist);
        }

        public Vector3 TargetPosition
        {
            set { targetPosition = value; }
            get { return targetPosition; }
        }

        public Vector3 Position
        {
            get { return position; }
        }

        public void SetPosition()
        {
            position.X = targetPosition.X + currentZoom;
            position.Z = targetPosition.Z + currentZoom;
            position.Y = currentElevation;
        }
    }
}
